﻿namespace BadHabit.WPFTools
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;

    /// <summary>
    /// A shaped window is a transparent window that should have its content, title bar and border drawed.
    /// You should provide the following element names at the XAML: TitleBar, MaximizeButton, MinimizeButton and CloseButton.
    /// </summary>
    public class ShapedWindow : Window
    {
        // used to emulate the maximize
        private double oldHeight;
        private double oldWidth;
        private double oldLeft;
        private double oldTop;

        private UIElement titleBar;
        private UIElement maximizeButton;
        private UIElement minimizeButton;
        private UIElement closeButton;

        /// <summary>
        /// Constructor.
        /// </summary>
        public ShapedWindow()
            : base()
        {
            Background = Brushes.Transparent;
            AllowsTransparency = true;

            this.Loaded += new RoutedEventHandler(this.ShapedWindow_Loaded);
        }

        public static void ShowAsSingle<T>(ref T w) where T : ShapedWindow, new()
        {
            if (w == null || w.IsVisible == false)
            {
                w = new T();
                w.ShowDialog();
            }
            else
            {
                w.BringIntoView();
            }
        }

        /// <summary>
        /// Links all the events to the window elements.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShapedWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.titleBar = this.Template.FindName("PART_TitleBar", this) as UIElement;
            if (this.titleBar != null)
            {
                this.titleBar.MouseLeftButtonDown += new MouseButtonEventHandler(this.TitleBarMouseLeftButtonDown);
            }

            this.maximizeButton = this.Template.FindName("PART_MaximizeButton", this) as UIElement;
            if (this.maximizeButton != null)
            {
                this.maximizeButton.MouseLeftButtonDown += new MouseButtonEventHandler(this.MaximizeButtonMouseLeftButtonDown);
            }

            this.minimizeButton = this.Template.FindName("PART_MinimizeButton", this) as UIElement;
            if (this.minimizeButton != null)
            {
                this.minimizeButton.MouseLeftButtonDown += new MouseButtonEventHandler(this.MinimizeButtonMouseLeftButtonDown);
            }

            this.closeButton = this.Template.FindName("PART_CloseButton", this) as FrameworkElement;
            if (this.closeButton != null)
            {
                if (this.closeButton is Button)
                {
                    Button closeButtonB = this.closeButton as Button;
                    closeButtonB.Click += new RoutedEventHandler(this.CloseButtonBClick);
                }
                else
                {
                    this.closeButton.MouseLeftButtonDown += new MouseButtonEventHandler(this.CloseButtonMouseLeftButtonDown);
                }
            }
        }

        private void CloseButtonBClick(object sender, RoutedEventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CloseButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Close();
        }

        /// <summary>
        /// When the minimize button is clicked, minimizes it.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MinimizeButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// When the maximize button is clicked expands the window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MaximizeButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.IsMaximized = !this.IsMaximized;
        }

        /// <summary>
        /// When the title bar is clicked, change its states ou drags it.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TitleBarMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.OnTitleBarMouseLeftDown(e);
        }

        /// <summary>
        /// Gets and Sets whenever the window is maximized.
        /// When using a tranparent window, the maximized state overlaps the
        /// task bar. This fix this ugly behaviour.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public bool IsMaximized
        {
            get
            {
                return Width == System.Windows.SystemParameters.PrimaryScreenWidth && Height == System.Windows.SystemParameters.WorkArea.Height;
            }
            
            set
            {
                if (ResizeMode == ResizeMode.NoResize)
                {
                    return;
                }

                WindowState = WindowState.Normal;
                if (value)
                {
                    this.oldTop = this.Top;
                    this.oldLeft = this.Left;
                    this.oldHeight = this.ActualHeight;
                    this.oldWidth = this.ActualWidth;
                    this.Left = 0;
                    this.Top = 0;
                    this.Width = System.Windows.SystemParameters.WorkArea.Width;
                    this.Height = System.Windows.SystemParameters.WorkArea.Height;
                }
                else
                {
                    this.Top = this.oldTop;
                    this.Left = this.oldLeft;
                    this.Width = this.oldWidth;
                    this.Height = this.oldHeight;
                }
            }
        }

        /// <summary>
        /// If was a drag, drag it, otherwize changes it states.
        /// </summary>
        /// <param name="e"></param>
        protected void OnTitleBarMouseLeftDown(MouseButtonEventArgs e)
        {
            if (e.ClickCount >= 2)
            {
                this.IsMaximized = !this.IsMaximized;
            }
            else
            {
                this.DragMove();
            }
        }
    }
}
